#pragma once

#include "..\\headers.default.h"
#include "..\\headers.cv.h"
#include "..\\headers.classification.h"
#include "..\\headers.ipfe.h"
#include "..\\headers.object_detection.h"

using namespace loirey;

namespace binary_ipfe_classification
{
	class CBicExample
	{
	public:
		int ParentFileSet;
		int FileIndex;
		bool fIsPos;
		double real_x, real_y;
		double ipl_scale_x;
		double ipl_scale_y;

	public:
		CBicExample();
		CBicExample(const CImagePyramidPosition& ipp);
		void ToIpp(CImagePyramidPosition& DstIpp) const;
	public:
		virtual bool InputFromBinaryFile(FILE* FIN);
		virtual void OutputToBinaryFile(FILE* FOUT) const;
	public:
		virtual bool InputFromStream(istream& inStream);
		virtual void OutputToStream(ostream& outStream) const;
	public:
		static bool InputListFromFile(CSimpleTypeArray<CBicExample>& DstExampleList, string strFN_SrcExampleList);
		static void OutputListToFile(string strFN_DstExampleList, const CSimpleTypeArray<CBicExample>& SrcExampleList);
		static bool InputListFromBinaryFile(CSimpleTypeArray<CBicExample>& DstExampleList, string strFN_SrcExampleList);
		static void OutputListToBinaryFile(string strFN_DstExampleList, const CSimpleTypeArray<CBicExample>& SrcExampleList);
	};

	class CBicExampleConfig
	{
	public:
		static const int FIT_BOX_STYLE_TIGHT = 0;
		static const int FIT_BOX_STYLE_CONTEXT = 1;
		static const int FIT_BOX_STYLE_MIN_SIZE = 2;

	public:
		int PosExample_ImageExtent;
		double PosExample_xScale;
		double PosExample_yScale;
	public:
		double PosExample_ShakeRange_xCenter;
		double PosExample_ShakeRange_yCenter;
		double PosExample_ShakeRange_xScale;
		double PosExample_ShakeRange_yScale;
	public:
		int StdObjectTight_W;
		int StdObjectTight_H;
		double StdObjectScaleRatio_xTolerance;
		double StdObjectScaleRatio_yTolerance;
	public:
		int StdObjectContext_W;
		int StdObjectContext_H;
		double StdObjectCenter_xOffset;
		double StdObjectCenter_yOffset;
	public:
		int Scan_FitBox_Style;
		int Scan_FitBox_Min_W;
		int Scan_FitBox_Min_H;
	//public:
	//	int Scan_PixelSample_Margin;
	//	double Scan_PixelSample_Rate;

	public:
		CBicExampleConfig();
	public:
		void SetPosExampleBasicConfiguration(int ImageExtent, double xScale, double yScale);
		void SetPosExampleShakingConfiguration(double xCenter, double yCenter, double xScale, double yScale);
		void SetStdObjectTightConfiguration(
			int Std_W, int Std_H,
			double xTolerance, double yTolerance
			);
		void SetStdObjectContextConfiguration(
			int Std_W, int Std_H,
			double Center_xOffset, double Center_yOffset
			);
		void SetScanningFitBoxConfiguration(
			int Style, int Min_W, int Min_H);
		//void SetScanningPixelSamplingConfiguration(
		//	int SampleMargin,
		//	double SampleRate);
	public:
		virtual void AdjustScale(double& xScale, double& yScale) const;
	public:
		virtual void FixTightBoxScale(CRectBox<double>& DstTightBox, CRectBox<double> SrcTightBox) const;
		virtual double GetIplScaleFromTightBox(CRectBox<double> SrcTightBox) const;
		virtual void MakeContextBoxFromTightBox(CRectBox<double>& DstContextBox, CRectBox<double> SrcTightBox) const;
		virtual void MakeTightBoxFromContextBox(CRectBox<double>& DstTightBox, CRectBox<double> SrcContextBox) const;
		virtual void MakeContextBoxFromExample(CRectBox<double>& DstContextBox, const CBicExample& SrcExample) const;
		virtual void MakeExampleFromContextBox(CBicExample& DstExample, const CRectBox<double>& SrcContextBox) const;
		virtual void MakeTightBoxFromExample(CRectBox<double>& DstTightBox, const CBicExample& SrcExample) const;
		virtual void MakeExampleFromTightBox(CBicExample& DstExample, const CRectBox<double>& SrcTightBox) const;
		virtual void MakeTightBoxFromCenterAndIplScale(CRectBox<double>& DstTightBox, double CenterX, double CenterY, double IplScale) const;
		virtual void MakeContextBoxFromCenterAndIplScale(CRectBox<double>& DstContextBox, double CenterX, double CenterY, double IplScale) const;
		virtual void MakeExampleFromCenterAndIplScale(CBicExample& DstExample, double CenterX, double CenterY, double IplScale) const;
	public:
		virtual void BuildPosExample(
			CBicExample& DstExample,
			int ParentFileSet, int FileIndex) const;
		virtual void GeneratePosExampleList(
			CSimpleTypeArray<CBicExample>& DstExampleList, bool fAppendMode,
			int ParentFileSet, int FileIndex,
			int Amount, bool fFixFirstUnshakeable, bool fUniform_XY_Scale) const;
		virtual int GenerateNegExampleList(
			CSimpleTypeArray<CBicExample>& DstExampleList, bool fAppendMode,
			int Image_W, int Image_H,
			int PixelSampleMargin, double PixelSampleRate,
			int ScaleLevel, double ScaleFactor,
			int ParentFileSet, int FileIndex) const;
	};

	class CBicDetector
	{
	public:
		class CLayerResult
		{
		public:
			int LW, LH;
			double ipl_scale;
			CSimpleTypeArray<CCandidateDetection> CanDetList;
			CImg<double> imgConfidence;
		};

	public:
		double Scan_ScalingFactor;
		int Scan_SampleMargin;
		double Scan_SampleRate;
		double ConfidenceThreshold;
	public:
		CMeanShiftNMS::CParameters MeanShiftConfig;
		CBicExampleConfig BicExampleConfig;
		CImagePyramidPositionFeatureExtractor* pIPPFE;
		CBinaryClassifier* pImagePatchClassifier;
	public:
		int W, H;
		CImg<int> imgSrc;
		//CZoomableImage ZoomImage;

	public:
		CBicDetector();
	public:
		void SetConfidenceThreshold(double ConfidenceThreshold);
		void Init_IPPFE_and_Classifier(
			CImagePyramidPositionFeatureExtractor* pIPPFE,
			CBinaryClassifier* pImagePatchClassifier);
	public:
		void SetImage(string strFN_SrcImage);
		void SetImage(const CImg<int>& imgSrc);
		int ProcessImageLayer_ByScale(CLayerResult& DstResult, double ipl_scale, bool fUseConfidenceThreshold) const;
		int ProcessImageLayer(CLayerResult& DstResult, int LayerIndex, bool fUseConfidenceThreshold) const;
	public:
		void DoNMS(
			CSimpleTypeArray<CDetectionWithScore>& DstDetectionList,
			const CSimpleTypeArray<CCandidateDetection>& SrcCanDetList,
			bool fToTightBox) const;
	};

	class CBicExampleParentFileNameSet
	{
	public:
		int SetIndex;
		CSimpleTypeArray<string> FileNameList;
	};

	class CBicExampleFeatureDataSet : public CLabeledDataSetForClassification
	{
	public:
		CImagePyramidPositionFeatureExtractor* pIPPFE;
	protected:
		bool _fSharedIPPFE;
	public:
		CSimpleTypeArray<CBicExampleParentFileNameSet>* pList_BicExampleParentFileNameSet;
	protected:
		int _ImageHandle;
		int _LastParentFileSet, _LastFileIndex, _LastNode;
	public:
		string strFN_Pfx_ImageCacheHashName;
		int ExampleAmount;
		CSimpleTypeArray<CBicExample> ExampleList;

	public:
		CBicExampleFeatureDataSet();
		virtual ~CBicExampleFeatureDataSet();
	public:
		virtual void InitIPPFE(CImagePositionFeatureExtractor* pPrototypeIPFE, int CacheSize = 1);
		virtual void InitIPPFE(CImagePyramidPositionFeatureExtractor* pInitializedIPPFE, bool fShared);
	public:
		virtual void InitBicExampleParentFileNameSetList(
			CSimpleTypeArray<CBicExampleParentFileNameSet>* pList_BicExampleParentFileNameSet,
			string strFN_Pfx_ImageCacheHashName = "");
		//virtual void InitBicExampleList(const CSimpleTypeArray<CBicExample>& ExampleList);
		virtual void InitBicExampleList(string strFN_ExampleList);
		virtual void InitBicExampleList_Binary(string strFN_ExampleList);
	public:
		virtual void SetQuery(int NodeIndex);
		virtual double GetFeature(int FeatureIndex);
	public:
		virtual int GetFeatureDimension();
		virtual int GetExampleAmount();
		virtual int GetExampleLabel(int NodeIndex);
		virtual double GetExampleInitialWeight(int NodeIndex);
		virtual double GetExampleFeature(int NodeIndex, int FeatureIndex);
	public:
		virtual size_t GetMemoryUsage() const;
	};
}

